﻿using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
using System;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;

namespace Jimmy.NinjiectDemo.Service
{
    public class NinjectConfig
    {
        private static readonly Bootstrapper bootstrapper = new Bootstrapper();

        public static void Start()
        {
#if WebCondition
            DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
#endif
            DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
            bootstrapper.Initialize(CreateKernel);
        }

        public static void Stop()
        {
            bootstrapper.ShutDown();
        }

        public static IKernel Kernel { get; private set; }

        private static IKernel CreateKernel()
        {
            Kernel = new StandardKernel();
            try
            {
                Kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
                Kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

                // 注册MVC
                DependencyResolver.SetResolver(new NinjectDependencyResolverForMvc(Kernel));
                // 注册WebApi
                GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(Kernel);
                // 注册其他接口及实现的
                RegisterServices(Kernel);

                return Kernel;
            }
            catch
            {
                Kernel.Dispose();
                throw;
            }
        }

        private static void RegisterServices(IKernel kernel)
        {
            var assembly = Assembly.GetAssembly(typeof(NinjectConfig));
            var types = assembly.GetTypes();
            var interfaceTypes = types.ToList().Where(t => t.IsInterface);
            var classTypes = types.ToList().Where(t => t.IsClass);
            if (null != interfaceTypes && interfaceTypes.Any())
            {
                interfaceTypes.ToList().ForEach(interfaceItem =>
                {
                    var classImpItems = classTypes.Where(c => interfaceItem.IsAssignableFrom(c));
                    if (null != classImpItems && classImpItems.Any())
                    {
                        classImpItems.ToList().ForEach(imp => kernel.Bind(new Type[] { interfaceItem }).To(imp));
                    }
                });
            }

            KernelBuilder.Build(kernel);
        }

        public static object GetService(Type serviceType)
        {
            return Kernel.TryGet(serviceType);
        }

        public static T GetService<T>() where T : class
        {
            var serviceType = typeof(T);
            if(null != serviceType)
            {
                return Kernel.TryGet(serviceType) as T;
            }

            return default(T);
        }
    }
}